import lldb
import struct

def read_utf16_string(process, addr, size):
    error = lldb.SBError()
    mem = process.ReadMemory(addr, size * 2, error)
    if error.Success():
        return mem.decode('utf-16', errors='replace')
    return '<invalid memory>'

def qstring_summary(valobj, _):
    data_ptr = valobj.GetChildMemberWithName("d").GetChildMemberWithName("ptr")
    if not data_ptr.IsValid() or data_ptr.GetValueAsUnsigned() == 0:
        return '""'
    try:
        size = valobj.GetChildMemberWithName("d").GetChildMemberWithName("size").GetValueAsUnsigned()
        raw_ptr = data_ptr.GetValueAsUnsigned()
        process = valobj.GetTarget().GetProcess()
        error = lldb.SBError()
        mem = process.ReadMemory(raw_ptr, size * 2, error)
        if error.Success():
            utf16 = struct.unpack("<{}H".format(size), mem)
            s = ''.join(chr(c) for c in utf16)
            return '"' + s + '"'
    except Exception as e:
        return f"<error: {str(e)}>"
    return "<error reading QString>"

def qstringlist_summary(valobj, _):
    try:
        d = valobj.GetChildMemberWithName("d")
        if not d.IsValid():
            return "[]"
        size = d.GetChildMemberWithName("size").GetValueAsUnsigned(0)
        if size == 0:
            return "[]"
        data = d.GetChildMemberWithName("ptr")
        if not data.IsValid():
            return "[]"
        data_address = data.GetValueAsUnsigned(0)
        item_size = valobj.GetType().GetTemplateArgumentType(0).GetByteSize()
        process = valobj.GetTarget().GetProcess()
        result = []
        for i in range(size):
            element_addr = data_address + i * item_size
            element = valobj.CreateValueFromAddress(f"[{i}]", element_addr, valobj.GetType().GetTemplateArgumentType(0))
            if element.IsValid():
                q_str = qstring_summary(element, _)
                result.append(q_str)
            else:
                result.append("<invalid>")
        return "[" + ", ".join(result) + "]"
    except Exception as e:
        return f"<QStringList error: {str(e)}>"



def qurl_summary(valobj, _):
    try:
        string = valobj.GetChildMemberWithName('d').GetChildMemberWithName('url')
        return 'QUrl(' + qstring_summary(string, _) + ')'
    except Exception as e:
        return f'<QUrl error: {e}>'

def qbytearray_summary(valobj, _):
    try:
        # 获取私有数据结构 d
        d = valobj.GetChildMemberWithName("d")
        if not d.IsValid():
            return '"<invalid>"'

        # 获取 size 和 ptr
        size = d.GetChildMemberWithName("size").GetValueAsSigned(-1)
        if size < 0:
            return '"<invalid size>"'

        data_ptr = d.GetChildMemberWithName("ptr")
        if not data_ptr.IsValid() or data_ptr.GetValueAsUnsigned(0) == 0:
            return '"<null>"'

        # 读取内存中的原始字节
        raw_ptr = data_ptr.GetValueAsUnsigned(0)
        process = valobj.GetTarget().GetProcess()
        error = lldb.SBError()
        mem = process.ReadMemory(raw_ptr, size, error)

        if not error.Success():
            return f'"<memory read error: {error.GetCString()}>"'

        # 将字节转换为字符串（Latin-1 保证单字节到字符）
        byte_list = list(mem)
        s = ''.join(chr(b) if 32 <= b <= 126 else '.' for b in byte_list)

        # 截断显示，防止输出过长
        MAX_DISPLAY_LENGTH = 128
        if len(s) > MAX_DISPLAY_LENGTH:
            s = s[:MAX_DISPLAY_LENGTH] + "..."

        # 返回带引号的字符串摘要
        return f'"{s}"'

    except Exception as e:
        return f'"<error: {str(e)}>"'

# === Summary for QList<T> ===
def qlist_summary(valobj, _):
    try:
        d = valobj.GetChildMemberWithName("d")
        if not d.IsValid():
            return "[]"
        size = d.GetChildMemberWithName("size").GetValueAsSigned(-1)
        if size < 0:
            return "[]"
        if size == 0:
            return "[]"

        data = d.GetChildMemberWithName("ptr")
        if not data.IsValid():
            return "[]"

        item_type = valobj.GetType().GetTemplateArgumentType(0)
        item_size = item_type.GetByteSize()
        base_address = data.GetValueAsUnsigned(0)

        process = valobj.GetTarget().GetProcess()
        elements = []
        # 显示前 5 个元素
        max_display = min(size, 20)
        elements = []
        for i in range(max_display):
            element_address = base_address + i * item_size
            element = valobj.CreateValueFromAddress(f"[{i}]", element_address, item_type)

            if not element.IsValid():
                elements.append("<invalid>")
                continue

            summary = element.GetSummary()
            value = element.GetValue()
            if summary:
                elements.append(summary)
            elif value:
                elements.append(str(value))
            else:
                elements.append("<no value>")

        if size > max_display:
            elements.append("...")
        return f"[{size}] {{{', '.join(elements)}}}"
    except Exception as e:
        return f"[error: {str(e)}]"

# === Synthetic Children Provider for QList<T> ===
class QListSynthProvider:
    def __init__(self, valobj, _):
        self.valobj = valobj
        self.update()

    def update(self):
        d = self.valobj.GetChildMemberWithName("d")
        self.size = d.GetChildMemberWithName("size").GetValueAsSigned(0)
        self.data = d.GetChildMemberWithName("ptr")

    def num_children(self):
        return max(0, self.size)

    def get_child_at_index(self, index):
        if index < 0 or index >= self.size:
            return None
        item_type = self.valobj.GetType().GetTemplateArgumentType(0)
        item_size = item_type.GetByteSize()
        offset = index * item_size
        return self.data.CreateChildAtOffset(f"[{index}]", offset, item_type)

    def has_children(self):
        return True

def qvariant_summary(valobj, _):
    try:
        typeId = valobj.GetChildMemberWithName('d').GetChildMemberWithName('type').GetValueAsUnsigned()
        return f'<QVariant type={typeId}>'
    except Exception as e:
        return f'<QVariant error: {e}>'

def qsize_summary(valobj, _):
    try:
        w = valobj.GetChildMemberWithName('wd').GetValueAsSigned()
        h = valobj.GetChildMemberWithName('ht').GetValueAsSigned()
        return f'QSize({w}, {h})'
    except Exception as e:
        return f'<QSize error: {e}>'

def qpoint_summary(valobj, _):
    try:
        x = valobj.GetChildMemberWithName('xp').GetValueAsSigned()
        y = valobj.GetChildMemberWithName('yp').GetValueAsSigned()
        return f'QPoint({x}, {y})'
    except Exception as e:
        return f'<QPoint error: {e}>'

def qrect_summary(valobj, _):
    try:
        x = valobj.GetChildMemberWithName('x1').GetValueAsSigned()
        y = valobj.GetChildMemberWithName('y1').GetValueAsSigned()
        x2 = valobj.GetChildMemberWithName('x2').GetValueAsSigned()
        y2 = valobj.GetChildMemberWithName('y2').GetValueAsSigned()
        return f'QRect({x}, {y}, {x2 - x}, {y2 - y})'
    except Exception as e:
        return f'<QRect error: {e}>'

def qcolor_summary(valobj, _):
    try:
        r = valobj.GetChildMemberWithName('ct').GetChildMemberWithName('rgba').GetChildMemberWithName('red').GetValueAsUnsigned()
        g = valobj.GetChildMemberWithName('ct').GetChildMemberWithName('rgba').GetChildMemberWithName('green').GetValueAsUnsigned()
        b = valobj.GetChildMemberWithName('ct').GetChildMemberWithName('rgba').GetChildMemberWithName('blue').GetValueAsUnsigned()
        a = valobj.GetChildMemberWithName('ct').GetChildMemberWithName('rgba').GetChildMemberWithName('alpha').GetValueAsUnsigned()
        return f'QColor(r={r}, g={g}, b={b}, a={a})'
    except Exception as e:
        return f'<QColor error: {e}>'

def __lldb_init_module(debugger, _):
    debugger.HandleCommand('type summary add -F qt6_pretty.qstring_summary QString -e -h')
    debugger.HandleCommand('type summary add -F qt6_pretty.qstringlist_summary QStringList -e -h')
    debugger.HandleCommand('type summary add -F qt6_pretty.qstringlist_summary "QList<QString>" -e -h')

    # Summary for QList<T>
    debugger.HandleCommand('type summary add -F qt6_pretty.qlist_summary "QList<.*>" -e -h')

    # Synthetic Children Provider for QList<T>
    debugger.HandleCommand('type synthetic add -l qt6_pretty.QListSynthProvider "QList<.*>" -e -h')

    debugger.HandleCommand('type summary add -F qt6_pretty.qurl_summary QUrl -e -h')
    debugger.HandleCommand('type summary add -F qt6_pretty.qbytearray_summary QByteArray -e -h')
    debugger.HandleCommand('type summary add -F qt6_pretty.qvariant_summary QVariant -e -h')
    debugger.HandleCommand('type summary add -F qt6_pretty.qsize_summary QSize -e -h')
    debugger.HandleCommand('type summary add -F qt6_pretty.qpoint_summary QPoint -e -h')
    debugger.HandleCommand('type summary add -F qt6_pretty.qrect_summary QRect -e -h')
    debugger.HandleCommand('type summary add -F qt6_pretty.qcolor_summary QColor -e -h')

    print("✅ Qt6 LLDB pretty printers loaded.")
